#ifndef XENENGIN_RENDERER_SHADER_HPP
#define XENENGIN_RENDERER_SHADER_HPP

#include "xen/pch.hpp"
#include "xen/log.hpp"
#include "xen/core.hpp"

namespace Xen {

class Shader {
public:
    static Ref<Shader> CreateFromFile(const std::string& name, const std::string& path);
    static Ref<Shader> CreateFromSource(const std::string& name, const std::string& vertex_source, const std::string& fragment_source);

    virtual ~Shader() = default;

    virtual const std::string& GetName() const = 0;
    virtual void Bind() const = 0;
    virtual void Unbind() const = 0;

    virtual void UniformMat3(const std::string& name, const glm::mat3&) = 0;
    virtual void UniformMat4(const std::string& name, const glm::mat4&) = 0;
    virtual void UniformInt(const std::string& name, int) = 0;
    virtual void UniformInt2(const std::string& name, const glm::ivec2&) = 0;
    virtual void UniformInt3(const std::string& name, const glm::ivec3&) = 0;
    virtual void UniformInt4(const std::string& name, const glm::ivec4&) = 0;
    virtual void UniformFloat(const std::string& name, float) = 0;
    virtual void UniformFloat2(const std::string& name, const glm::vec2&) = 0;
    virtual void UniformFloat3(const std::string& name, const glm::vec3&) = 0;
    virtual void UniformFloat4(const std::string& name, const glm::vec4&) = 0;
};

class ShaderLibrary final {
public:
    void Add(const Ref<Shader>& shader);
    Ref<Shader> Load(const std::string& name, const std::string& path);

    Ref<Shader> Get(const std::string& name);
    bool Exists(const std::string& name) const;

private:
    std::unordered_map<std::string, Ref<Shader>> shader_map_;
};

}

#endif
